package com.virtual.rerijaapps.pet.animation;

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;

public class FlipAnimation extends Animation
{

	private Camera camera;

	private View fromView;

	private View toView;

	private float centerX;
	
	private float centerY;

	private final ScaleUpDownEnum scaleType;

	public static final float SCALE_DEFAULT = 0.65f;

	private float scale;

	private boolean forward = true;

	public FlipAnimation( View fromView, View toView, int duration, ScaleUpDownEnum scaleType, float scale )
	{
		this.fromView = fromView;
		this.toView = toView;
		this.scaleType = ( null == scaleType ) ? ScaleUpDownEnum.SCALE_CYCLE : scaleType;
		this.scale = ( 0 >= scale || 1 <= scale ) ? SCALE_DEFAULT : scale;

		setDuration( duration );
		setFillAfter( true );
		setInterpolator( new AccelerateDecelerateInterpolator() );
	}

	public void reverse()
	{
		forward = false;
		View switchView = toView;
		toView = fromView;
		fromView = switchView;
	}

	@Override
	public void initialize( int width, int height, int parentWidth, int parentHeight )
	{
		super.initialize( width, height, parentWidth, parentHeight );
		centerX = width / 2;
		centerY = height / 2;
		camera = new Camera();
	}

	@Override
	protected void applyTransformation( float interpolatedTime, Transformation t )
	{
		final double radians = Math.PI * interpolatedTime;
		float degrees = (float) ( 180.0 * radians / Math.PI );

		if ( 0.5f <= interpolatedTime )
		{
			degrees -= 180.f;
			fromView.setVisibility( View.GONE );
			toView.setVisibility( View.VISIBLE );
		}

		degrees = ( forward ) ? -degrees : degrees;

		final Matrix matrix = t.getMatrix();
		camera.save();
		camera.rotateY( degrees );
		camera.getMatrix( matrix );
		camera.restore();

		matrix.preTranslate( -centerX, -centerY );
		matrix.postTranslate( centerX, centerY );
		matrix.preScale( scaleType.getScale( scale, interpolatedTime ), scaleType.getScale( scale, interpolatedTime ), centerX,
						 centerY);
	}

	public static enum ScaleUpDownEnum
	{
		SCALE_UP,

		SCALE_DOWN,

		SCALE_CYCLE;

		public float getScale( float max, float iteration )
		{
			switch( this )
			{
				case SCALE_UP:
					return max + ( 1 - max ) * iteration;

				case SCALE_DOWN:
					return 1 - ( 1 - max ) * iteration;

				case SCALE_CYCLE:
					return ( 0.5 < iteration ) ? ( max + ( 1 - max ) * ( iteration - 0.5f ) * 2 ) : ( 1 - ( 1 - max ) * ( iteration * 2 ) );

				default:
					return 1;
			}
		}
	}
}
